﻿using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Collections.Generic;

namespace MosCraft.Utilities.Input
{
    public static class KeyboardHelper
    {
        /// <summary>
        /// Constructor
        /// </summary>
        static KeyboardHelper()
        {
            PreviousState = new bool[256];
            CurrentState = new bool[256];
        }

        /// <summary>
        /// Update the keyboard status.
        /// </summary>
        static internal void Update()
        {

            // Scan each key
            for (int i = 0; i < 256; i++)
            {
                if (PreviousState[i] != CurrentState[i])
                {
                    if (CurrentState[i])
                        OnKeyDown(new PreviewKeyDownEventArgs((Keys)i));
                    else
                        OnKeyUp(new KeyEventArgs((Keys)i));
                }
                PreviousState[i] = CurrentState[i];
                CurrentState[i] = (PInvoke.GetKeyState(i) & 0x8000) != 0;
            }
        }

        /// <summary>
        /// Gets if a key is pressed
        /// </summary>
        /// <param name="key">Key</param>
        /// <returns>True if pressed</returns>
        public static bool IsKeyPress(Keys key)
        {
            int value = (int)key;
            if (value > CurrentState.Length)
                return false;


            return CurrentState[value];
        }

        /// <summary>
        /// Gets if a key is released
        /// </summary>
        /// <param name="key">Key</param>
        /// <returns>True if released</returns>
        public static bool IsKeyReleased(Keys key)
        {
            return !CurrentState[(int)key];
        }

        /// <summary>
        /// Gets if a new key is down
        /// </summary>
        /// <param name="key">Key</param>
        /// <returns>True if down</returns>
        public static bool IsNewKeyPress(Keys key)
        {
            return CurrentState[(int)key] && !PreviousState[(int)key];
        }

        /// <summary>
        /// Gets if a new key is up
        /// </summary>
        /// <param name="key">Key</param>
        /// <returns>True if up</returns>
        public static bool IsNewKeyUp(Keys key)
        {
            return !CurrentState[(int)key] && PreviousState[(int)key];
        }

        /// <summary>
        /// Gets a list of all pressed keys
        /// </summary>
        /// <returns>List of pressed keys</returns>
        public static List<Keys> GetPressedKeys()
        {
            List<Keys> list = new List<Keys>();

            for (int i = 0; i < 254; i++)
            {
                if (IsKeyPress((Keys)i))
                    list.Add((Keys)i);
            }
            return list;
        }


        /// <summary>
        /// Gets a list of all released keys
        /// </summary>
        /// <returns>List of released keys</returns>
        public static List<Keys> GetReleasedKeys()
        {
            List<Keys> list = new List<Keys>();

            for (int i = 0; i < 254; i++)
            {
                if (IsKeyReleased((Keys)i))
                    list.Add((Keys)i);
            }
            return list;
        }

        #region OnEvents

        /// <summary>
        /// KeyDown event
        /// </summary>
        /// <param name="e"></param>
        static internal void OnKeyDown(PreviewKeyDownEventArgs e)
        {
            if (KeyDown != null)
                KeyDown(null, e);
        }


        /// <summary>
        /// KeyUp event
        /// </summary>
        /// <param name="e"></param>
        static internal void OnKeyUp(KeyEventArgs e)
        {
            if (KeyUp != null)
                KeyUp(null, e);
        }

        #endregion

        #region Events

        /// <summary>
        ///  Event fired when a KeyDown occur
        /// </summary>
        public static event EventHandler<PreviewKeyDownEventArgs> KeyDown;


        /// <summary>
        /// Event fired when a KeyUp occurs
        /// </summary>
        public static event EventHandler<KeyEventArgs> KeyUp;


        #endregion

        #region Properties

        /// <summary>
        /// Current state of the keyboard
        /// </summary>
        static bool[] CurrentState;

        /// <summary>
        /// Previous state pf the keyboard
        /// </summary>
        static bool[] PreviousState;

        #endregion
    }
}
